package net.gz01.wallet.web.controller.api;

import static net.gz01.wallet.web.config.FDDConfig.APP_ID;
import static net.gz01.wallet.web.config.FDDConfig.APP_SECRET;
import static net.gz01.wallet.web.config.FDDConfig.HOST;
import static net.gz01.wallet.web.config.FDDConfig.V;
import static net.gz01.wallet.web.config.FDDConfig.getContract_id;
import static net.gz01.wallet.web.config.FDDConfig.getTransaction_id;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import net.gz01.wallet.common.WalletMD5;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;
import com.jfinal.aop.Before;
import com.jfinal.aop.Clear;
import com.jfinal.aop.Duang;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.tx.Tx;

import lombok.extern.slf4j.Slf4j;
import net.gz01.util.ZODate;
import net.gz01.util.ZOJson;
import net.gz01.util.ZOMD5;
import net.gz01.util.ZOString;
import net.gz01.wallet.channel.fadada.FadadaChannel;
import net.gz01.wallet.common.ZOIDGenerate;
import net.gz01.wallet.message.NetSignReq;
import net.gz01.wallet.message.NetSignResp;
import net.gz01.wallet.message.RealCompanyReq;
import net.gz01.wallet.message.RealCompanyResp;
import net.gz01.wallet.web.config.SystemConfig;
import net.gz01.wallet.web.config.SystemEnum;
import net.gz01.wallet.web.config.SystemEnum.Resp;
import net.gz01.wallet.web.controller.BaseController;
import net.gz01.wallet.web.controller.api.sdk.client.FddClientBase;
import net.gz01.wallet.web.controller.api.sdk.client.authForfadada.ApplyCert;
import net.gz01.wallet.web.controller.api.ylmodel.AddAcount;
import net.gz01.wallet.web.controller.api.ylmodel.AddUser;
import net.gz01.wallet.web.controller.api.ylmodel.AddUserResp;
import net.gz01.wallet.web.controller.api.ylmodel.BaseHeader;
import net.gz01.wallet.web.controller.api.ylmodel.BaseYLResp;
import net.gz01.wallet.web.controller.api.ylmodel.CasherDesk;
import net.gz01.wallet.web.controller.api.ylmodel.UpdateUser;
import net.gz01.wallet.web.controller.api.ylmodel.YLQueryResp;
import net.gz01.wallet.web.model.HeTongConfig;
import net.gz01.wallet.web.model.Merch;
import net.gz01.wallet.web.model.MerchRole;
import net.gz01.wallet.web.model.MerchUser;
import net.gz01.wallet.web.model.TradeConfig;
import net.gz01.wallet.web.model.TradeOrder;
import net.gz01.wallet.web.model.YouliAccount;
import net.gz01.wallet.web.model.base.FddOrder;
import net.gz01.wallet.web.service.AccountService;

@Slf4j
@Clear
public class YouliApiController extends BaseController {

	private final String apiKey = SystemConfig.config.get("apiyl_key");
	private final String orgCode = SystemConfig.config.get("org_code");
	private final Long defaultMerchRoleId = SystemConfig.config.getLong("defaultMerchRoleId");
	private final boolean thatOK = true;

	private AccountService accountService = Duang.duang(AccountService.class);

	/**
	 * 2.1新注册商户的同步接口
	 */
	@Before(Tx.class)
	public void addUser() {
		BaseYLResp resp = new BaseYLResp();
		try {
			String res = getStringFromRequest();
			resp = new BaseYLResp();
			if (!res.startsWith("{")) {
				resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "数据格式错误!");
				renderJson(resp);
				return;
			}
			AddUser addUser = ZOJson.toObject(res, AddUser.class);
			resp = commonValidate(addUser);
			if (!SystemEnum.Resp.Success.getCode().equals(resp.getRespCode())) {
				renderJson(resp);
				return;
			}

			// 签名验证
			resp = this.verifySign(resp, res, apiKey, addUser.getSign());
			if (Resp.Fail.getCode().equals(resp.getRespCode())) {
				renderJson(resp);
				return;
			}

			MerchUser user = MerchUser.dao.selectByUserName(addUser.getUserName(), addUser.getInCome());
			Merch merch = Merch.dao.selectByCusterCode(addUser.getCusterCode());
			if (user != null && merch != null && user.getMerchCode().equals(merch.getCode())) {
				AddUserResp userResp = new AddUserResp();
				userResp.setCodeAndMsg(SystemEnum.Resp.Success.getCode(), "重复成功:" + SystemEnum.Resp.Success.getMsg());
				userResp.setVirtualCode(merch.getCode());
				userResp.setVersion(addUser.getVersion());
				if (!merch.getIsVerify() || !merch.getIsSign()) {
					userResp.setIsSignOK("0");
				}
				userResp.setSign(ZOMD5.sortSign(userResp, apiKey));
				renderJson(userResp);
				return;
			}
			if (StringUtils.isEmpty(addUser.getAccountType())) {
				addUser.setAccountType("1");// 默认个人实名网签
			}
			// 查询出默认商户模板的数据
			Merch defualtMerch = Merch.dao.selectDefaultMerch();
			if (defualtMerch == null) {
				resp.setCodeAndMsg(Resp.Fail.getCode(), "严重错误-->默认商户模板不存在！！");
				renderJson(resp);
				log.error("严重错误-->默认商户模板不存在-->" + res);
				return;
			}

			if (merch == null && user == null) {
				user = new MerchUser();
				merch = new Merch();
				// 创建新的商户和用户
				createMerchAndUser(merch, user, addUser, defualtMerch);
			} else if (merch != null && user == null) {// 支持一个商户关联多个登陆用户
				user = new MerchUser();
				createMerchUser(merch, user, addUser);
			} else {
				resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "同步数据错误:" + res);
				renderJson(resp);
				return;
			}
			// 生成虚账账号
			accountService.addAccount(merch.getCode(), merch.getName());
			// 使用默认的手续费，风控规则，渠道编号保存交易策略
			TradeConfig.dao.autoCreate(merch.getCode());

			AddUserResp userResp = new AddUserResp();
			userResp.setCodeAndMsg(SystemEnum.Resp.Success.getCode(), SystemEnum.Resp.Success.getMsg());
			userResp.setVirtualCode(merch.getCode());
			userResp.setVersion(addUser.getVersion());
			userResp.setIsSignOK("0");
			Map<String, String> respMap = ZOJson.toMap(JSON.toJSONString(userResp));
			userResp.setSign(ZOMD5.sortSign(respMap, apiKey, "sign"));
			renderJson(userResp);
		} catch (Exception e) {
			log.error("系统异常" + e);
			renderJson(resp.setCodeAndMsg(Resp.Fail.getCode(), "系统异常"));
		}
	}

	/**
	 * 2.1.1同步用户的收款卡信息
	 * 保留，有可能使用---同步银行卡提款账户
	 */
	@Before(Tx.class)
	public void addAccount() {
		BaseYLResp resp = new BaseYLResp();
		try {
			String res = getStringFromRequest();
			AddAcount addAcount = ZOJson.toObject(res, AddAcount.class);
			resp = commonValidate(addAcount);
			if (!SystemEnum.Resp.Success.getCode().equals(resp.getRespCode())) {
				renderJson(resp);
				return;
			}
			// 签名验证
			resp = this.verifySign(resp, res, apiKey, addAcount.getSign());
			if (Resp.Fail.getCode().equals(resp.getRespCode())) {
				renderJson(resp);
				return;
			}

		} catch (Exception e) {
			log.error("系统异常" + e);
			renderJson(resp.setCodeAndMsg(Resp.Fail.getCode(), "系统异常"));
		}
	}

	/**
	 * 2.1.0修改用户信息接口
	 */
	@Before(Tx.class)
	public void updateUser() {
		BaseYLResp resp = new BaseYLResp();
		try {
			String res = getStringFromRequest();
			UpdateUser updateUser = ZOJson.toObject(res, UpdateUser.class);
			resp = commonValidate(updateUser);
			if (!SystemEnum.Resp.Success.getCode().equals(resp.getRespCode())) {
				renderJson(resp);
				return;
			}
			// 签名验证
			resp = this.verifySign(resp, res, apiKey, updateUser.getSign());
			if (Resp.Fail.getCode().equals(resp.getRespCode())) {
				renderJson(resp);
				return;
			}

			Merch merch = Merch.dao.selectByCusterCode(updateUser.getOldCusterCode());
			MerchUser merchUser = MerchUser.dao.selectByMerCode(merch.getCode());
			merch.setName(updateUser.getCusterName());
			merch.setMerchNamePy(ZOString.convertStartPinyin(merch.getName()));
			merchUser.setUserName(updateUser.getUserName());
			merchUser.setPassword(updateUser.getPassWord());
			merchUser.setUpdateTime(ZODate.getDateTime());
			merchUser.setName(merch.getName());
			merchUser.update();
			merch.update();

			AddUserResp userResp = new AddUserResp();
			userResp.setCodeAndMsg(SystemEnum.Resp.Success.getCode(), SystemEnum.Resp.Success.getMsg());
			userResp.setVirtualCode(merch.getCode());
			userResp.setVersion(updateUser.getVersion());

			Map<String, String> respMap = ZOJson.toMap(JSON.toJSONString(userResp));
			userResp.setSign(ZOMD5.sortSign(respMap, apiKey, "sign"));
			renderJson(userResp);
		} catch (Exception e) {
			log.error("系统异常" + e);
			renderJson(resp.setCodeAndMsg(Resp.Fail.getCode(), "系统异常"));
		}
	}

	/**
	 *  钱包首页接口
	 */
	public void home() {
		String userName = getPara("userName");
		String passWord = getPara("passWord");
		String version = getPara("version");
		String type = getPara("inCome");
		String timestamp = getPara("timestamp");
		String sign = getPara("sign");
		String me = getPara("me");
		BaseYLResp resp = new BaseYLResp();
		if (StringUtils.isEmpty(me)) {
			BaseHeader baseReq = new BaseHeader();
			baseReq.setSign(sign);
			baseReq.setVersion(version);
			baseReq.setTimestamp(timestamp);
			resp = commonValidate(baseReq);
			if (!SystemEnum.Resp.Success.getCode().equals(resp.getRespCode())) {
				renderJson(resp);
				return;
			}
			TreeMap<String, String> treeMap = new TreeMap<>();
			treeMap.put("userName", userName);
			treeMap.put("passWord", passWord);
			treeMap.put("version", version);
			treeMap.put("timestamp", timestamp);
			treeMap.put("inCome", type);
			String mysign = ZOMD5.sortSign(treeMap, apiKey);
			log.info("服务器签名:" + mysign);
			if (!mysign.equals(sign)) {
				resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "签名验证错误!");
				renderJson(resp);
				return;
			}
		}
		MerchUser user = MerchUser.dao.loginFind(userName, passWord, type);
		if (user == null) {
			renderText("用户名或者密码错误");
			return;
		}
		getSession().setAttribute(MerchUser.SessionKey, user);
		redirect("/customer/index");
	}

	/**
	 * 实名和网签接口
	 */
	@Before(Tx.class)
	public void netSign() {
		String userName = getPara("userName");
		String passWord = getPara("passWord");
		String type = getPara("type");
		String notifyUrl = getPara("notifyUrl");
		String returnUrl = getPara("returnUrl");
		String version = getPara("version");
		String timestamp = getPara("timestamp");
		String inCome = getPara("inCome");
		String sign = getPara("sign");
		String me = getPara("me");
		BaseYLResp resp = new BaseYLResp();
		if (StringUtils.isEmpty(me)) {
			BaseHeader baseReq = new BaseHeader();
			baseReq.setSign(sign);
			baseReq.setVersion(version);
			baseReq.setTimestamp(timestamp);
			resp = commonValidate(baseReq);
			if (!SystemEnum.Resp.Success.getCode().equals(resp.getRespCode())) {
				renderJson(resp);
				return;
			}
			if (StringUtils.isEmpty(notifyUrl)) {
				resp.setCodeAndMsg("01", "异步回调的URL不能为空");
				renderJson(resp);
				return;
			}
			TreeMap<String, String> treeMap = new TreeMap<>();
			treeMap.put("userName", userName);
			treeMap.put("passWord", passWord);
			treeMap.put("type", type);
			treeMap.put("notifyUrl", notifyUrl);
			treeMap.put("returnUrl", returnUrl);
			treeMap.put("version", version);
			treeMap.put("timestamp", timestamp);
			treeMap.put("inCome", inCome);

			// 签名验证
			resp = this.verifySign(resp, treeMap, apiKey, sign);
			if (Resp.Fail.getCode().equals(resp.getRespCode())) {
				renderJson(resp);
				return;
			}
		}
		MerchUser user = MerchUser.dao.loginFind(userName, passWord, inCome);
		if (user == null) {
			renderHtml("用户名或者密码错误!");
			return;
		}
		Merch merch = Merch.dao.selectByMerchCode(user.getMerchCode());
		FddOrder fddOrder = FddOrder.dao.selectByUserCode(false, merch.getCode());
		if ((merch.getIsVerify()) || (fddOrder != null && fddOrder.getResCode().equals(SystemEnum.Resp.Success.getCode()))) {
			if (thatOK) {// 流程签署为真---回到流程页面继续
				redirect("/customer/index?payUrl=" + fddOrder.getReturnUrl());
				return;
			}
		}
		RealCompanyReq req = new RealCompanyReq();
		req.setOpen_id(merch.getCode());
		req.setAccount_type(type);
		req.setNotify_url(notifyUrl);
		req.setReturn_url(returnUrl);
		RealCompanyResp companyResp = new FadadaChannel().realNameCompany(req);
		log.info("实名认证返回:" + ZOJson.toString(companyResp));
		if (StringUtils.isNotEmpty(companyResp.getUrl())) {
			redirect(companyResp.getUrl());
			return;
		} else {
			renderJson(companyResp);
			return;
		}
	}


    @Before(Tx.class)  //网签接口
    public void netSignAuto(){
        String userName = getPara("userName");
        String passWord = getPara("passWord");
        String type = getPara("type");
        String notifyUrl = getPara("notifyUrl");
        String returnUrl = getPara("returnUrl");
        String version = getPara("version");
        String timestamp = getPara("timestamp");
        String sign = getPara("sign");
        String inCome = getPara("inCome");

        String me = getPara("me");
        BaseYLResp resp = new BaseYLResp();
        boolean isCheckSign = true;
        if(StringUtils.isEmpty(me)){
            BaseHeader baseReq = new BaseHeader();
            baseReq.setSign(sign);
            baseReq.setVersion(version);
            baseReq.setTimestamp(timestamp);
            resp = commonValidate(baseReq);
            if (!SystemEnum.Resp.Success.getCode().equals(resp.getRespCode())) {
                renderJson(resp);
                return;
            }
            if (StringUtils.isEmpty(notifyUrl)) {
                resp.setCodeAndMsg("01", "异步回调的URL不能为空");
                renderJson(resp);
                return;
            }


            TreeMap<String, String> treeMap = new TreeMap<>();
            treeMap.put("userName", userName);
            treeMap.put("passWord", passWord);
            treeMap.put("type", type);
            treeMap.put("notifyUrl", notifyUrl);
            treeMap.put("returnUrl", returnUrl);
            treeMap.put("version", version);
            treeMap.put("timestamp", timestamp);
            treeMap.put("inCome", inCome);
            // 签名验证
 			resp = this.verifySign(resp, treeMap, apiKey, sign);
 			if (isCheckSign && Resp.Fail.getCode().equals(resp.getRespCode())) {
 				renderJson(resp);
 				return;
         	}
        }
        MerchUser user = MerchUser.dao.loginFind(userName, passWord, inCome);
        if(user == null){
            renderHtml("用户名或者密码错误!");
            return;
        }
        Merch merch = Merch.dao.selectByMerchCode(user.getMerchCode());
        {
            FddOrder fddOrder = FddOrder.dao.selectByUserCode(false, merch.getCode());
            if((merch.getIsVerify()) || (fddOrder!=null && fddOrder.getResCode().equals(SystemEnum.Resp.Success.getCode()))){
                //不需要实名认证了， 直接调用网签接口：
                NetSignReq req = new NetSignReq();
                HeTongConfig heTongConfig =  HeTongConfig.dao.selectByEnable();
                req.setHeTongUrl(SystemConfig.config.get("myUrl") + heTongConfig.getPdfUrl());
                log.info("要上传的合同URL:" + req.getHeTongUrl());
                req.setCustomer_id(merch.getCustomerId());
                req.setDoc_title(heTongConfig.getTitle());
                req.setSign_keyword(heTongConfig.getSignKeyword());
                req.setOpen_id(merch.getCode());
                req.setContract_id(getContract_id());//合同编号随机生成);
                req.setTransaction_id(getTransaction_id());
                req.setNotify_url(fddOrder.getNotifyUrl());
                req.setReturn_url(fddOrder.getReturnUrl());
                NetSignResp netSignResp =  new FadadaChannel().netsignNet(req);

                if(netSignResp.getRespCode().equals("00")){
                    redirect(netSignResp.getUrl());
                }else {
                    renderText(ZOJson.toString(netSignResp));
                }
                return;
            }else {
                renderHtml("请先实名认证完成后，再调用网签接口!");
            }
        }
        renderHtml("用户名或者密码错误!");
    }


    //实名认证同步回调, 因为这个url是被法大大重定向过来的，所以需要重新保存登录信息到  Session
    public void fdd_verify_return(){
        String transactionNo = getPara("transactionNo");
        String status = getPara("status");
        String authenticationType = getPara("authenticationType");

		String parameterString = transactionNo + ";" + status + ";" + authenticationType;
		log.info("实名认证--->收到FDD同步通知-> \r\n" + parameterString);

        FddOrder order = FddOrder.dao.selectByOrder(false, transactionNo);
        if(order!=null && order.getUserCode()!=null && order.getType()!=null){
            Merch user = Merch.dao.selectByMerchCode(order.getUserCode());
            MerchUser merchUser = MerchUser.dao.selectByMerCode(order.getUserCode());
            if("00".equals(order.getResCode()) && user.getIsVerify()){
                if(thatOK) {//自动签署为真
                    redirect("/customer/index?payUrl=" + order.getReturnUrl() + "&api=api&loginType=" + merchUser.getUserType() + "&login=" + merchUser.getUserName());
                    return;
                }
            }else {
                if("1".equals(order.getType())){//个人实名认证的
                    if("2".equals(status)){
                        ApplyCert applyCert = new ApplyCert(APP_ID,APP_SECRET,V,HOST);
                        String customer_id = order.getCustomerId();
                        String verified_serialno= order.getFddOrderNo();
                        String result = applyCert.invokeApplyCert(customer_id,verified_serialno);
                        log.info("FDD-->个人实名认证的正式申请返回:" + result);//FDD-->实名认证的正式申请返回:{"code":1,"msg":"success"}
                        if("1".equals(JSON.parseObject(result).getString("code"))) {
                            order.setResCode("00");
                            order.setFinishTime(ZODate.getDateTime());
                            order.update();
                            user.setIsVerify(true);
                            user.setCustomerId(order.getCustomerId());
                            user.update();
                        }
                    }
                }
                if("2".equals(order.getType())){//企业实名认证的
                    if("4".equals(status)){
                        ApplyCert applyCert = new ApplyCert(APP_ID,APP_SECRET,V,HOST);
                        String customer_id = order.getCustomerId();
                        String verified_serialno= order.getFddOrderNo();
                        String result = applyCert.invokeApplyCert(customer_id,verified_serialno);
                        log.info("FDD-->企业实名认证的正式申请返回:" + result);//FDD-->实名认证的正式申请返回:{"code":1,"msg":"success"}
                        if("1".equals(JSON.parseObject(result).getString("code"))) {
                            order.setResCode("00");
                            order.setFinishTime(ZODate.getDateTime());
                            order.update();
                            user.setIsVerify(true);
                            user.setCustomerId(order.getCustomerId());
                            user.update();
                        }
                    }
                }
                if("00".equals(order.getResCode()) && user.getIsVerify()){
                    if(thatOK){//自动签署为真
                        redirect("/customer/index?payUrl=" + order.getReturnUrl());
                        return;
                    }
                }else {
                    renderHtml("请重新登录完成实名认证网签!");
                }
            }
        }
    }

	/**
	 *  2.10 调起支付收银台接口
	 */
	@Before(Tx.class)
	public void casherdesk() {
		String res = getStringFromRequest();
		String resJson = "";
		if (StringUtils.isBlank(res)) {
			Map<String, String> resMap = ParamUtil.getParamMap(getRequest());
			resJson = JSON.toJSONString(resMap);
		} else if (res.startsWith("{")) {
			resJson = res;
			log.info("1.收到json数据:" + resJson);
		} else {
			Map<String, String> resMap = ParamUtil.getParamsMap(res, "UTF-8");
			resJson = JSON.toJSONString(resMap);
			log.info("2.收到json数据:" + resJson);
		}
		log.info("json数据:" + resJson);
		CasherDesk casherDesk = ZOJson.toObject(resJson, CasherDesk.class);
		BaseYLResp resp = commonValidate(casherDesk);
		if (!SystemEnum.Resp.Success.getCode().equals(resp.getRespCode())) {
			renderJson(resp);
			return;
		}
		if (StringUtils.isEmpty(casherDesk.getPayType())) {
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "支付方式不能为空!");
			renderJson(resp);
			return;
		}

		// 签名验证
		resp = this.verifySign(resp, casherDesk, apiKey, casherDesk.getSign());
		if (Resp.Fail.getCode().equals(resp.getRespCode())) {
			renderJson(resp);
			return;
		}
		// 付款方必须是消费者角色
		MerchUser merchUser = MerchUser.dao.loginFind(casherDesk.getUserName(), casherDesk.getPassWord(), "1");
		if (merchUser == null) {// 付款方
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "消费者用户名和密码错误!");
			renderJson(resp);
			return;
		}
		Merch merchBuyer = Merch.dao.selectByMerchCode(merchUser.getMerchCode());
		if (merchBuyer == null) {// 付款方
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "消费者用户关联的钱包用户信息错误!");
			renderJson(resp);
			return;
		}

		if (TradeOrder.dao.isExitMerCodeNo(casherDesk.getMallOrderNo())) {
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "001.订单号不能重复处理:" + casherDesk.getMallOrderNo());
			renderJson(resp);
			return;
		}

		// 收款方
		Merch merchSeller = Merch.dao.selectByCusterCode(casherDesk.getSeller());
		if (merchSeller == null) {
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "商家收款方客户号不存在:" + casherDesk.getSeller());
			renderJson(resp);
			return;
		}
		if (!"2".equals(merchSeller.getUserType())) {
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "非商家角色，不能收款:" + casherDesk.getSeller());
			renderJson(resp);
		}
		if (merchSeller.getIsVerify() == null || !merchSeller.getIsVerify()) {
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "1.此商家:" + merchSeller.getName() + "没有收款权限，未做实名网签");
			renderJson(resp);
			return;
		}
		if (merchSeller.getIsSign() == null || !merchSeller.getIsSign()) {
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "2.此商家:" + merchSeller.getName() + "没有收款权限，未做实名网签");
			renderJson(resp);
			return;
		}

		String bizTpye = ("1".equals(casherDesk.getPayType()) ? SystemEnum.BizType.Charge.getValue()
				: SystemEnum.BizType.ExpenseIn.getValue());
		TradeConfig tradeConfig = TradeConfig.dao.select(merchSeller.getCode(), bizTpye);
		if (tradeConfig == null) {
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "收款商户方交易策略配置错误:" + casherDesk.getSeller());
			renderJson(resp);
			return;
		}
		List<YouliAccount> accountList = YouliAccount.dao.selectAll();
		if (accountList == null || accountList.isEmpty()) {
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "error:0099:收款对公账户配置错误!");
			renderJson(resp);
			return;
		}

		TradeOrder tradeOrder = new TradeOrder();
		if ("1".equals(casherDesk.getPayType())) {// 充值单
			tradeOrder.createChargeOrder(merchBuyer, casherDesk, merchSeller, tradeConfig, accountList);
		} else {// 钱包支付单
			tradeOrder.createOrderPay(merchBuyer, casherDesk, merchSeller, tradeConfig);
		}

		getSession().setAttribute(MerchUser.SessionKey, merchUser);
		String myurl = "/customer/casherdesk/index" + "?" + "orderNo=" + tradeOrder.getOrderNo() + "&payType="
				+ casherDesk.getPayType();

		// 线下转账不需要消费者开通钱包功能
		if (!"1".equals(casherDesk.getPayType())) {
			if (merchBuyer.getIsSign() == null || merchBuyer.getIsVerify() == null || !merchBuyer.getIsVerify() || !merchBuyer.getIsSign()) {
				String url = "/customer/index?payUrl=" + myurl + "&login=" + merchUser.getUserName() + "&loginType=1&api=api";
				redirect(url);
				return;
			}
		}
		redirect(myurl);
	}

	/**
	 * 2.10.1 钱包支付的订单查询接口
	 */
	@Before(Tx.class)
	public void query() {
		String res = getStringFromRequest();
		log.info("查询收到数据:" + res);
		CasherDesk casherDesk = ZOJson.toObject(res, CasherDesk.class);
		BaseYLResp resp = commonValidate(casherDesk);
		Map<String, String> reqMap = ZOJson.toMap(res);
		if (!SystemEnum.Resp.Success.getCode().equals(resp.getRespCode())) {
			renderJson(resp);
			return;
		}
		// 签名验证
		resp = this.verifySign(resp, reqMap, apiKey, casherDesk.getSign());
		if (Resp.Fail.getCode().equals(resp.getRespCode())) {
			renderJson(resp);
			return;
		}

		TradeOrder tradeOrder = TradeOrder.dao.selectMerCodeNo(casherDesk.getMallOrderNo(), SystemEnum.BizType.ExpenseOut.getValue());
		if (tradeOrder == null) {
			resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "订单号不存在!");
			renderJson(resp);
			return;
		}

		YLQueryResp ylQueryResp = new YLQueryResp();
		ylQueryResp.setCodeAndMsg(SystemEnum.Resp.Success.getCode(), "查询通信OK");
		ylQueryResp.setMallOrderNo(tradeOrder.getOutOrderNo());
		ylQueryResp.setOrderStatus(tradeOrder.getOrderStatus());
		ylQueryResp.setPayTime(tradeOrder.getPayTime());
		ylQueryResp.setTimestamp(System.currentTimeMillis() + "");
		ylQueryResp.setVersion("V1.0");

		String sign = ZOMD5.sortSign(ylQueryResp, apiKey);
		ylQueryResp.setSign(sign);
		renderJson(ylQueryResp);
	}

	/**
	 * 签署合同的异步回调
	 */
	public void fdd_sign() {
		String transaction_id = getPara("transaction_id");
		String result_code = getPara("result_code");
		String download_url = getPara("download_url");
		String viewpdf_url = getPara("viewpdf_url");

		log.info("合同签署异步--->收到FDD异步通知-> \r\n" + transaction_id + ";" + result_code + ";" + viewpdf_url);

		Map<String, String> resMap = new TreeMap<>();
		resMap.put("transaction_id", transaction_id);
		resMap.put("result_code", result_code);
		resMap.put("download_url", download_url);
		resMap.put("viewpdf_url", viewpdf_url);
		if ("3000".equals(result_code)) {
			FddOrder fddOrder = FddOrder.dao.selectByOrder(true, transaction_id);
			Merch merch = Merch.dao.selectByMerchCode(fddOrder.getUserCode());
			if ((fddOrder != null && !"00".equals(fddOrder.getResCode()))) {
				fddOrder.setResCode("00");
				fddOrder.setJsondata(ZOJson.toString(resMap));
				fddOrder.setFinishTime(ZODate.getDateTime());
				if (merch != null) {
					merch.setIsSign(true);
					merch.setDownloadUrl(download_url);
					merch.setViewpdfUrl(viewpdf_url);
					merch.setContractId(fddOrder.getContractId());
					merch.setTransactionId(fddOrder.getFddOrderNo());
					merch.update();
					fddOrder.update();
				}
			}

			FddClientBase base = new FddClientBase(APP_ID, APP_SECRET, V, HOST);
			String contract_id = fddOrder.getContractId();
			base.invokeContractFilling(contract_id);
		}
		renderHtml(result_code);
	}

	/**
	 *  合同签署的同步回调
	 */
	public void fdd_sign_return() {
		log.info("合同签署同步--->收到FDD同步通知-> \r\n");
		String transaction_id = getPara("transaction_id");
		String result_code = getPara("result_code");
		String download_url = getPara("download_url");
		String viewpdf_url = getPara("viewpdf_url");
		if ("3000".equals(result_code)) {
			FddOrder fddOrder = FddOrder.dao.selectByOrder(true, transaction_id);
			Merch merch = Merch.dao.selectByMerchCode(fddOrder.getUserCode());
			if (fddOrder != null && !"00".equals(fddOrder.getResCode())) {
				fddOrder.setResCode("00");
				fddOrder.setFinishTime(ZODate.getDateTime());
				if (merch != null && merch.getCode() != null && !merch.getIsSign()) {
					merch.setIsSign(true);
					merch.setDownloadUrl(download_url);
					merch.setViewpdfUrl(viewpdf_url);
					merch.setContractId(fddOrder.getContractId());
					merch.setTransactionId(fddOrder.getFddOrderNo());
					merch.update();
					fddOrder.update();
				}
				// 因为这个url是被法大大重定向过来的，所以需要重新保存登录信息到 Session
				MerchUser merchUser = (MerchUser) getSession().getAttribute("loginMerchUser");
				if (merchUser == null || merchUser.getMerchCode() == null) {
					MerchUser loginUser = MerchUser.dao.selectByMerCode(merchUser.getMerchCode());
					log.info("1重写登录回话:---->getSession().setAttribute(loginUser);");
					getSession().setAttribute("loginMerchUser", loginUser);
				}
			} else if (fddOrder != null && "00".equals(fddOrder.getResCode())) {
				// 因为这个url是被法大大重定向过来的，所以需要重新保存登录信息到 Session
				MerchUser merchUser = (MerchUser) getSession().getAttribute("loginMerchUser");
				if (merchUser == null || merchUser.getMerchCode() == null) {
					MerchUser loginUser = MerchUser.dao.selectByMerCode(merchUser.getMerchCode());
					log.info("2重写登录回话:---->getSession().setAttribute(loginUser);");
					getSession().setAttribute("loginMerchUser", loginUser);
				}
			}
			redirect(fddOrder.getReturnUrl());
		}
	}

	/**
	 * 测试异步回调接口
	 */
	public void testPush() {
		String parameterString = "";
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(getRequest().getInputStream(), "UTF-8"));
			StringBuffer buffer = new StringBuffer();
			String string;
			while ((string = reader.readLine()) != null) {
				buffer.append(string);
			}
			parameterString = URLDecoder.decode(buffer.toString(), "UTF-8");

		} catch (Exception e) {
			e.printStackTrace();
		}

		log.info("订单异步回调:" + parameterString);

		renderText("SUCCESS");
	}

	private BaseYLResp commonValidate(BaseHeader req) {
		BaseYLResp resp = new BaseYLResp();
		if (StrKit.isBlank(req.getVersion())) {
			return resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "版本号不允许为空");
		}
		if (StrKit.isBlank(req.getSign())) {
			return resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "签名字段不允许为空");
		}

		if (StrKit.isBlank(req.getTimestamp())) {
			return resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "时间字段不允许为空");
		}

		return resp.setCodeAndMsg(SystemEnum.Resp.Success.getCode(), SystemEnum.Resp.Success.getMsg());
	}

	private void createMerchAndUser(Merch merch, MerchUser user, AddUser addUser, Merch defualtMerch) {
		boolean isCompany = false;
		merch.setUserType("1");// 消费者
		if ("2".equals(addUser.getInCome())) {// 商户角色
			isCompany = true;
			merch.setUserType("2");
		}
		if (defualtMerch != null) {
			merch.setYouliAccountRuleId(defualtMerch.getYouliAccountRuleId());// 默认的友利收款账户，制单充值使用！
		}
		merch.setCusterCode(addUser.getCusterCode());
		merch.setCode(ZOIDGenerate.getNextMerchCode(isCompany));
		merch.setName(addUser.getCusterName());
		merch.setCreateTime(ZODate.getDateTime());
		merch.setEnable(true);
		merch.setOrgCode(orgCode);
		merch.setAccountType(addUser.getAccountType());
		merch.setMerchNamePy(ZOString.convertStartPinyin(merch.getName()));

		user.setMerchCode(merch.getCode());
		user.setOrgCode(orgCode);
		user.setUserName(addUser.getUserName());
		user.setPhone(addUser.getUserName());
		user.setUserType(merch.getUserType());
		user.setPassword(addUser.getPassWord());
		user.setName(merch.getName());
		user.setEnable(true);
		MerchRole role = MerchRole.dao.findById(defaultMerchRoleId);
		user.setRoleId(role.getId());
		user.setUpdateTime(ZODate.getDateTime());
		user.save();
		merch.save();
	}

	private void createMerchUser(Merch merch, MerchUser user, AddUser addUser) {
		user.setMerchCode(merch.getCode());
		user.setOrgCode(orgCode);
		user.setUserName(addUser.getUserName());
		user.setPhone(addUser.getUserName());
		user.setUserType(merch.getUserType());
		user.setPassword(addUser.getPassWord());
		user.setName(merch.getName());
		user.setEnable(true);
		MerchRole role = MerchRole.dao.findById(defaultMerchRoleId);
		user.setRoleId(role.getId());
		user.setUpdateTime(ZODate.getDateTime());
		user.save();
	}

	/**
	 * 签名验证
	 *
	 * @param resp
	 * @param signObj
	 * @param key
	 * @param sign
	 * @return
	 */
	private BaseYLResp verifySign(BaseYLResp resp, Object signObj, String key, String sign) {
		String serviceSign = WalletMD5.sortSign(signObj, key);
		log.info("服务器签名:" + serviceSign);
		if (!serviceSign.equals(sign)) {
			return resp.setCodeAndMsg(SystemEnum.Resp.Fail.getCode(), "签名验证错误!");
		}
		return resp;
	}

}
